home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / DiskUtil / CD-ROM / CDDA-1.3.lha / CDDA / CDDA.c < prev    next >
C/C++ Source or Header  |  1994-01-30  |  34KB  |  1,672 lines

  1. ;/*
  2. SC PARAMS=REGISTER NMINC MCCONS STREQ NOWVRET STRMERGE NOSTKCHK UTILLIB OPTIMIZE OPTTIME OPTINLINE MODIFIED IGNORE=73 CDDA.c
  3. SLINK CDDA.o TO CDDA LIB LIB:sc.lib LIB:amiga.lib SC SD ND NOICONS
  4. Quit
  5. */
  6.  
  7. /*
  8. **    CDDA - A program to replay digital audio data read from a
  9. **           Sony CD-ROM drive.
  10. **
  11. **    Copyright © 1993-1994 by Olaf `Olsen' Barthel
  12. **        This is a freeware release.
  13. */
  14.  
  15.     /* Avoid a nasty type conflict in older include files. */
  16.  
  17. #define CheckIO foo
  18.  
  19.     /* System includes */
  20.  
  21. #include <devices/scsidisk.h>
  22. #include <devices/trackdisk.h>
  23. #include <devices/audio.h>
  24.  
  25. #include <exec/execbase.h>
  26. #include <exec/memory.h>
  27.  
  28. #include <dos/dosextens.h>
  29. #include <dos/dostags.h>
  30. #include <dos/rdargs.h>
  31. #include <dos/dosasl.h>
  32.  
  33. #include <hardware/cia.h>
  34.  
  35. #include <clib/utility_protos.h>
  36. #include <clib/exec_protos.h>
  37. #include <clib/dos_protos.h>
  38. #include <clib/alib_protos.h>
  39. #include <clib/macros.h>
  40.  
  41. #include <pragmas/utility_pragmas.h>
  42. #include <pragmas/exec_pragmas.h>
  43. #include <pragmas/dos_pragmas.h>
  44.  
  45. #include <string.h>
  46.  
  47.     /* Get the CheckIO prototype right. */
  48.  
  49. #undef CheckIO
  50.  
  51. struct IORequest *CheckIO(struct IORequest *);
  52.  
  53.     /* The CIA A base address. */
  54.  
  55. #ifndef ciaa
  56. extern struct CIA __far ciaa;
  57. #endif    /* ciaa */
  58.  
  59.     /* Command line template. */
  60.  
  61. #define TEMPLATE    "DEVICE/K,UNIT/K/N,TRACK/N,FROM/K/N,TO/K/N,NUM/K/N,MAX/K/N,VERBOSE/S"
  62.  
  63.     /* The argument vector offsets. */
  64.  
  65. enum    {    ARG_DEVICE,ARG_UNIT,ARG_TRACK,ARG_FROM,ARG_TO,ARG_NUM,ARG_MAX,ARG_VERBOSE,
  66.  
  67.         ARGCOUNT
  68.     };
  69.  
  70.     /* Player task priority and stack size. */
  71.  
  72. #define CHILD_PRI    5
  73. #define CHILD_STACK    8192
  74.  
  75.     /* Default SCSI device name and unit number. */
  76.  
  77. #define SCSI_DEVICE    "scsi.device"
  78. #define SCSI_UNIT    2
  79.  
  80.     /* The signal mask associated with a MsgPort. */
  81.  
  82. #define PORTMASK(p)    (1L << ((struct MsgPort *)(p)) -> mp_SigBit)
  83.  
  84.     /* Some signal masks. */
  85.  
  86. #define SIG_HANDSHAKE    SIGF_SINGLE
  87. #define SIG_KILL    SIGBREAKF_CTRL_C
  88. #define SIG_SYNC    SIGBREAKF_CTRL_F
  89. #define SIG_CHILD    PORTMASK(ChildPort)
  90.  
  91.     /* The size of an audio data buffer and the
  92.      * number of blocks per packet (= 1 second of data).
  93.      */
  94.  
  95. #define BUFFER_SIZE    22050
  96. #define BLOCKS_PER_PKT    75
  97.  
  98.     /* Amiga audio channel allocation bits. */
  99.  
  100. #define LEFT0F        1
  101. #define RIGHT0F        2
  102. #define RIGHT1F        4
  103. #define LEFT1F        8
  104.  
  105.     /* SCSI command `test unit ready'. */
  106.  
  107. struct TestUnitReady
  108. {
  109.     UBYTE    Command,
  110.         Pad,
  111.         Reserved[3],
  112.         Control;
  113. };
  114.  
  115.     /* SCSI command `inquiry'. */
  116.  
  117. struct Inquiry
  118. {
  119.     UBYTE    Command,
  120.         Pad,
  121.         PageCode,
  122.         Reserved,
  123.         AllocationLength,
  124.         Control;
  125. };
  126.  
  127.     /* The data structure to be filled by the inquiry command. */
  128.  
  129. struct InquiryData
  130. {
  131.     UBYTE    PeripheralType,
  132.         DeviceTypeModifier,
  133.         Version,
  134.         Reserved[5],
  135.         Vendor[8],
  136.         Product[16],
  137.         Revision[4];
  138. };
  139.  
  140.     /* SCSI command `read table of contents'. */
  141.  
  142. struct ReadTOC
  143. {
  144.     UBYTE    Command,
  145.         Pad,
  146.         Reserved[4],
  147.         StartingTrack;
  148.     UBYTE    Alloc1,Alloc2;
  149.     UBYTE    Control;
  150. };
  151.  
  152.     /* The data structure to be filled in by the
  153.      * readtoc command.
  154.      */
  155.  
  156. struct FullTOC
  157. {
  158.     UWORD    DataLength;
  159.     UBYTE    FirstTrack,
  160.         LastTrack;
  161.  
  162.     struct
  163.     {
  164.         UBYTE    Reserved1,
  165.             Control,
  166.             TrackNumber,
  167.             Reserved2;
  168.         ULONG    Address;
  169.     } TOC[100];
  170. };
  171.  
  172.     /* Sony vendor unique command to read digital
  173.      * audio data.
  174.      */
  175.  
  176. struct ReadCDDA
  177. {
  178.     UBYTE        Command,
  179.             Pad;
  180.     ULONG        Address,
  181.             Count;
  182.     UBYTE        SubCode,
  183.             Control;
  184. };
  185.  
  186.     /* Digital audio data, as returned by the corresponding command. */
  187.  
  188. struct CDDASector
  189. {
  190.     struct CDDASample
  191.     {
  192.         UBYTE    LeftLSB,
  193.             LeftMSB,
  194.  
  195.             RightLSB,
  196.             RightMSB;
  197.     } Sample[588];
  198. };
  199.  
  200.     /* Handler->player task communications structure. */
  201.  
  202. struct AudioMessage
  203. {
  204.     struct Message         Message;
  205.     LONG             NumBlocks;
  206.     struct CDDASector    *Data;
  207. };
  208.  
  209.     /* Global library bases. */
  210.  
  211. struct ExecBase        *SysBase;
  212. struct DosLibrary    *DOSBase;
  213. struct Library        *UtilityBase;
  214.  
  215.     /* Command line arguments. */
  216.  
  217. struct RDArgs        *ArgsPtr;
  218. STRPTR            *Arg;
  219.  
  220.     /* Audio data. */
  221.  
  222. struct IOAudio        *AudioControl,
  223.             *AudioLeft,
  224.             *AudioRight;
  225. struct MsgPort        *AudioPort;
  226. BYTE            *ThisLeft,
  227.             *NextLeft,
  228.             *ThisRight,
  229.             *NextRight,
  230.             *AudioData;
  231. ULONG             Rate;
  232. LONG             FillCounter    = 0,
  233.              TotalPending    = 0;
  234. BOOL             AudioUsed    = FALSE,
  235.              AudioActive    = FALSE,
  236.              Verbose,
  237.              LED;
  238.  
  239.     /* Current sector and total number of sectors to read. */
  240.  
  241. LONG             Index,Total;
  242.  
  243.     /* SCSI device control data. */
  244.  
  245. struct MsgPort        *SCSIPort;
  246. struct IOExtTD        *SCSIRequest;
  247.  
  248. struct SCSICmd         SCSICmd;
  249. UBYTE             SenseBuffer[256];
  250.  
  251.     /* Data to be read from the device. */
  252.  
  253. struct FullTOC         FullTOC;
  254. struct InquiryData     InquiryData;
  255.  
  256.     /* Block queue access semaphore and number of
  257.      * packets in the queue.
  258.      */
  259.  
  260. struct SignalSemaphore     QueueSemaphore;
  261. LONG             QueueCount;
  262.  
  263.     /* Handler and player task data. */
  264.  
  265. struct Task        *Child;
  266. struct MsgPort        *ChildPort;
  267. struct Process        *Father;
  268. BOOL             FatherWaiting;
  269.  
  270.     /* Program version ID. */
  271.  
  272. STRPTR             VersionTag = "\0$VER: CDDA 1.3 (14.1.94)";
  273.  
  274.     /* Prototypes for this module. */
  275.  
  276. LONG __saveds        Main(VOID);
  277. VOID            SCSIExit(VOID);
  278. BOOL            SCSIInit(STRPTR Device,LONG Unit);
  279. VOID            AudioExit(VOID);
  280. BOOL            AudioInit(VOID);
  281. VOID            DeleteAudioMessage(struct AudioMessage *Message);
  282. struct AudioMessage *    CreateAudioMessage(LONG NumBlocks);
  283. VOID            StartAudio(VOID);
  284. VOID            ProcessAudio(VOID);
  285. VOID __saveds        ChildTask(VOID);
  286. VOID            CloseAll(VOID);
  287. BOOL            OpenAll(VOID);
  288. BYTE            ReadCDDASectors(APTR Buffer,LONG From,LONG Count);
  289. BYTE            TestUnitReady(VOID);
  290. BYTE            ReadTOC(VOID);
  291. BYTE            Inquire(VOID);
  292.  
  293.     /* Main():
  294.      *
  295.      *    The program entry point. No compiler startup code.
  296.      */
  297.  
  298. LONG __saveds
  299. Main()
  300. {
  301.     LONG Result = RETURN_FAIL;
  302.  
  303.         /* Open the resources. */
  304.  
  305.     if(OpenAll())
  306.     {
  307.         LONG             Blocks,MaxQueueSize;
  308.         struct AudioMessage    *Message;
  309.         BOOL             Stop        = FALSE,
  310.                      FirstMessage    = TRUE;
  311.  
  312.             /* Everything went fine so far. */
  313.  
  314.         Result = RETURN_OK;
  315.  
  316.             /* Get the maximum block queue size. */
  317.  
  318.         if(Arg[ARG_MAX])
  319.             MaxQueueSize = *(LONG *)Arg[ARG_MAX];
  320.         else
  321.             MaxQueueSize = 3;
  322.  
  323.             /* Safety check. */
  324.  
  325.         if(MaxQueueSize < 1)
  326.             MaxQueueSize = 1;
  327.  
  328.             /* Print the banner message. */
  329.  
  330.         FPrintf(Output(),"\33[1mCDDA\33[0m © Copyright 1993-1994 by Olaf `Olsen' Barthel, \33[4mAll rights reserved\33[0m\n");
  331.  
  332.             /* Play the tracks. */
  333.  
  334.         while(Total > 0)
  335.         {
  336.                 /* Stop playing? */
  337.  
  338.             if(CheckSignal(SIG_KILL))
  339.             {
  340.                 Stop = TRUE;
  341.  
  342.                 break;
  343.             }
  344.  
  345.                 /* Gain access to the block queue... */
  346.  
  347.             ObtainSemaphore(&QueueSemaphore);
  348.  
  349.                 /* More blocks in the queue than there
  350.                  * should be?
  351.                  */
  352.  
  353.             if(QueueCount > MaxQueueSize)
  354.             {
  355.                     /* Wait for the player task
  356.                      * to make room.
  357.                      */
  358.  
  359.                 Forbid();
  360.  
  361.                 ReleaseSemaphore(&QueueSemaphore);
  362.  
  363.                 SetSignal(0,SIG_HANDSHAKE);
  364.  
  365.                 FatherWaiting = TRUE;
  366.  
  367.                 Wait(SIG_HANDSHAKE);
  368.  
  369.                 FatherWaiting = FALSE;
  370.  
  371.                 Permit();
  372.             }
  373.             else
  374.                 ReleaseSemaphore(&QueueSemaphore);
  375.  
  376.                 /* Allocate another packet. */
  377.  
  378.             if(Message = CreateAudioMessage(Blocks = MIN(BLOCKS_PER_PKT,Total)))
  379.             {
  380.                     /* Read the data, we may need more than one
  381.                      * attempt if the drive feels unable to supply
  382.                      * the requested data immediately.
  383.                      */
  384.  
  385.                 while(ReadCDDASectors(Message -> Data,Index,Blocks))
  386.                 {
  387.                         /* Stop here? */
  388.  
  389.                     if(CheckSignal(SIG_KILL))
  390.                     {
  391.                         Stop = TRUE;
  392.  
  393.                         break;
  394.                     }
  395.  
  396.                         /* If in verbose mode, tell the user that
  397.                          * we are retrying to read the data.
  398.                          */
  399.  
  400.                     if(Verbose)
  401.                     {
  402.                         if(FirstMessage)
  403.                         {
  404.                             Printf("CDDA: Rereading sector #%ld\n",Index);
  405.  
  406.                             FirstMessage = FALSE;
  407.                         }
  408.                         else
  409.                             Printf("\033[ACDDA: Rereading sector #%ld\033[K\n",Index);
  410.                     }
  411.                 }
  412.  
  413.                     /* Read request aborted? */
  414.  
  415.                 if(Stop)
  416.                 {
  417.                         /* Clean up and exit. */
  418.  
  419.                     DeleteAudioMessage(Message);
  420.  
  421.                     break;
  422.                 }
  423.                 else
  424.                 {
  425.                         /* Add the data to the queue. */
  426.  
  427.                     PutMsg(ChildPort,&Message -> Message);
  428.  
  429.                     Total    -= Blocks;
  430.                     Index    += Blocks;
  431.                 }
  432.             }
  433.             else
  434.             {
  435.                     /* Stop here? */
  436.  
  437.                 if(CheckSignal(SIG_KILL))
  438.                 {
  439.                     Stop = TRUE;
  440.  
  441.                     break;
  442.                 }
  443.  
  444.                     /* If in verbose mode tell the user that
  445.                      * we will need to retry the memory
  446.                      * allocation.
  447.                      */
  448.  
  449.                 if(Verbose)
  450.                 {
  451.                     if(FirstMessage)
  452.                     {
  453.                         Printf("CDDA: Retrying memory allocation for sector #%ld\n",Index);
  454.  
  455.                         FirstMessage = FALSE;
  456.                     }
  457.                     else
  458.                         Printf("\033[ACDDA: Retrying memory allocation for sector #%ld\033[K\n",Index);
  459.                 }
  460.  
  461.                     /* Wait for the player task to make room. */
  462.  
  463.                 Forbid();
  464.  
  465.                 SetSignal(0,SIG_HANDSHAKE);
  466.  
  467.                 FatherWaiting = TRUE;
  468.  
  469.                 Wait(SIG_HANDSHAKE);
  470.  
  471.                 FatherWaiting = FALSE;
  472.  
  473.                 Permit();
  474.             }
  475.         }
  476.  
  477.             /* Issue the break message if necessary. */
  478.  
  479.         if(Stop)
  480.             PrintFault(ERROR_BREAK,"CDDA");
  481.         else
  482.         {
  483.                 /* Resync with player task, we
  484.                  * are about to exit cleanly.
  485.                  * In this case we want the player
  486.                  * task to process the remaining
  487.                  * audio data before we proceed to
  488.                  * tell it to shut down.
  489.                  */
  490.  
  491.             Forbid();
  492.  
  493.             SetSignal(0,SIG_HANDSHAKE);
  494.  
  495.             Signal(Child,SIG_SYNC);
  496.  
  497.             Wait(SIG_HANDSHAKE);
  498.  
  499.             Permit();
  500.         }
  501.     }
  502.  
  503.     CloseAll();
  504.  
  505.     return(Result);
  506. }
  507.  
  508.     /* SCSIExit():
  509.      *
  510.      *    Cleans up the scsi device data.
  511.      */
  512.  
  513. VOID
  514. SCSIExit()
  515. {
  516.     if(SCSIRequest)
  517.     {
  518.         if(SCSIRequest -> iotd_Req . io_Device)
  519.             CloseDevice(SCSIRequest);
  520.  
  521.         DeleteIORequest(SCSIRequest);
  522.  
  523.         SCSIRequest = NULL;
  524.     }
  525.  
  526.     if(SCSIPort)
  527.     {
  528.         DeleteMsgPort(SCSIPort);
  529.  
  530.         SCSIPort = NULL;
  531.     }
  532. }
  533.  
  534.     /* SCSIInit(STRPTR Device,LONG Unit):
  535.      *
  536.      *    Sets up the scsi device data.
  537.      */
  538.  
  539. BOOL
  540. SCSIInit(STRPTR Device,LONG Unit)
  541. {
  542.     if(!(SCSIPort = CreateMsgPort()))
  543.         return(FALSE);
  544.  
  545.     if(!(SCSIRequest = (struct IOExtTD *)CreateIORequest(SCSIPort,sizeof(struct IOExtTD))))
  546.         return(FALSE);
  547.  
  548.     if(OpenDevice(Device,Unit,SCSIRequest,NULL))
  549.         return(FALSE);
  550.  
  551.     return(TRUE);
  552. }
  553.  
  554.     /* AudioExit():
  555.      *
  556.      *    Cleans up the audio device data.
  557.      */
  558.  
  559. VOID
  560. AudioExit()
  561. {
  562.         /* Turn the power LED (= alias filter) back on/off. */
  563.  
  564.     Disable();
  565.  
  566.     if(LED)
  567.         ciaa . ciapra &= ~CIAF_LED;
  568.     else
  569.         ciaa . ciapra |= CIAF_LED;
  570.  
  571.     Enable();
  572.  
  573.         /* Clean up the left audio channel data. */
  574.  
  575.     if(AudioLeft)
  576.     {
  577.         if(AudioLeft -> ioa_Request . io_Device && AudioUsed)
  578.         {
  579.             if(!CheckIO(AudioLeft))
  580.             {
  581.                 AbortIO(AudioLeft);
  582.  
  583.                 WaitIO(AudioLeft);
  584.             }
  585.             else
  586.                 GetMsg(AudioPort);
  587.         }
  588.  
  589.         FreeVec(AudioLeft);
  590.  
  591.         AudioLeft = NULL;
  592.     }
  593.  
  594.         /* Clean up the right audio channel data. */
  595.  
  596.     if(AudioRight)
  597.     {
  598.         if(AudioRight -> ioa_Request . io_Device && AudioUsed)
  599.         {
  600.             if(!CheckIO(AudioRight))
  601.             {
  602.                 AbortIO(AudioRight);
  603.  
  604.                 WaitIO(AudioRight);
  605.             }
  606.             else
  607.                 GetMsg(AudioPort);
  608.         }
  609.  
  610.         FreeVec(AudioRight);
  611.  
  612.         AudioRight = NULL;
  613.     }
  614.  
  615.         /* Free the control request. */
  616.  
  617.     if(AudioControl)
  618.     {
  619.         if(AudioControl -> ioa_Request . io_Device)
  620.             CloseDevice(AudioControl);
  621.  
  622.         DeleteIORequest(AudioControl);
  623.  
  624.         AudioControl = NULL;
  625.     }
  626.  
  627.         /* Take care of the rest. */
  628.  
  629.     if(AudioPort)
  630.     {
  631.         DeleteMsgPort(AudioPort);
  632.  
  633.         AudioPort = NULL;
  634.     }
  635.  
  636.     if(AudioData)
  637.     {
  638.         FreeVec(AudioData);
  639.  
  640.         AudioData = NULL;
  641.     }
  642. }
  643.  
  644.     /* AudioInit():
  645.      *
  646.      *    Initialize the audio device driver data.
  647.      */
  648.  
  649. BOOL
  650. AudioInit()
  651. {
  652.         /* Audio channel allocation map which should
  653.          * allocate two different stereo channels.
  654.          */
  655.  
  656.     STATIC UBYTE AllocationMap[] =
  657.     {
  658.         LEFT0F | RIGHT0F,
  659.         LEFT0F | RIGHT1F,
  660.         LEFT1F | RIGHT0F,
  661.         LEFT1F | RIGHT1F
  662.     };
  663.  
  664.         /* Turn off the power LED (= alias filter). */
  665.  
  666.     Disable();
  667.  
  668.     if(ciaa . ciapra & CIAF_LED)
  669.         LED = FALSE;
  670.     else
  671.     {
  672.         LED = TRUE;
  673.  
  674.         ciaa . ciapra |= CIAF_LED;
  675.     }
  676.  
  677.     Enable();
  678.  
  679.         /* Allocate the data. */
  680.  
  681.     if(!(AudioData = (BYTE *)AllocVec(BUFFER_SIZE * 4,MEMF_CHIP | MEMF_CLEAR)))
  682.         return(FALSE);
  683.  
  684.     if(!(AudioPort = CreateMsgPort()))
  685.         return(FALSE);
  686.  
  687.     if(!(AudioControl = (struct IOAudio *)CreateIORequest(AudioPort,sizeof(struct IOAudio))))
  688.         return(FALSE);
  689.  
  690.     if(!(AudioLeft = (struct IOAudio *)AllocVec(sizeof(struct IOAudio),MEMF_PUBLIC)))
  691.         return(FALSE);
  692.  
  693.     if(!(AudioRight = (struct IOAudio *)AllocVec(sizeof(struct IOAudio),MEMF_PUBLIC)))
  694.         return(FALSE);
  695.  
  696.         /* Prepare for initialization. */
  697.  
  698.     AudioControl -> ioa_Request . io_Message . mn_Node . ln_Pri    = 127;
  699.     AudioControl -> ioa_Request . io_Command            = ADCMD_ALLOCATE;
  700.     AudioControl -> ioa_Request . io_Flags                = ADIOF_NOWAIT | ADIOF_PERVOL;
  701.     AudioControl -> ioa_Data                    = AllocationMap;
  702.     AudioControl -> ioa_Length                    = sizeof(AllocationMap);
  703.  
  704.         /* Open the audio device driver. */
  705.  
  706.     if(OpenDevice(AUDIONAME,NULL,AudioControl,NULL))
  707.         return(FALSE);
  708.  
  709.         /* Choose the right replay rate for 22,050 samples per second. */
  710.  
  711.     Rate = (SysBase -> ex_EClockFrequency * 5) / 22050;
  712.  
  713.         /* Clone the audio control request. */
  714.  
  715.     CopyMem(AudioControl,AudioLeft, sizeof(struct IOAudio));
  716.     CopyMem(AudioControl,AudioRight,sizeof(struct IOAudio));
  717.  
  718.         /* Split the channels. */
  719.  
  720.     AudioLeft  -> ioa_Request . io_Unit    = (struct Unit *)((ULONG)AudioLeft  -> ioa_Request . io_Unit & (LEFT0F  | LEFT1F));
  721.     AudioRight -> ioa_Request . io_Unit    = (struct Unit *)((ULONG)AudioRight -> ioa_Request . io_Unit & (RIGHT0F | RIGHT1F));
  722.  
  723.         /* Set up the double buffering data. */
  724.  
  725.     ThisLeft    = AudioData;
  726.     NextLeft    = ThisLeft + BUFFER_SIZE;
  727.     ThisRight    = NextLeft + BUFFER_SIZE;
  728.     NextRight    = ThisRight + BUFFER_SIZE;
  729.  
  730.     return(TRUE);
  731. }
  732.  
  733.     /* DeleteAudioMessage(struct AudioMessage *Message):
  734.      *
  735.      *    Delete an AudioMessage, clean up the associated data.
  736.      */
  737.  
  738. VOID
  739. DeleteAudioMessage(struct AudioMessage *Message)
  740. {
  741.     FreeVec(Message);
  742.  
  743.     ObtainSemaphore(&QueueSemaphore);
  744.  
  745.     QueueCount--;
  746.  
  747.     ReleaseSemaphore(&QueueSemaphore);
  748.  
  749.         /* Wake up the handler process. */
  750.  
  751.     if(FatherWaiting)
  752.         Signal(Father,SIG_HANDSHAKE);
  753. }
  754.  
  755.     /* CreateAudioMessage(LONG NumBlocks):
  756.      *
  757.      *    Create an AudioMessage, i.e. a message with auxilary data
  758.      *    space attached.
  759.      */
  760.  
  761. struct AudioMessage *
  762. CreateAudioMessage(LONG NumBlocks)
  763. {
  764.     struct AudioMessage *Message;
  765.  
  766.     if(Message = (struct AudioMessage *)AllocVec(sizeof(struct AudioMessage) + 15 + NumBlocks * sizeof(struct CDDASector),MEMF_ANY | MEMF_PUBLIC))
  767.     {
  768.         ULONG Place = ((ULONG)(Message + 1) + 15) & ~15;
  769.  
  770.         Message -> Message . mn_Length    = sizeof(struct AudioMessage) + 15 + NumBlocks * sizeof(struct CDDASector);
  771.         Message -> NumBlocks        = NumBlocks;
  772.         Message -> Data            = (struct CDDASector *)Place;
  773.  
  774.         ObtainSemaphore(&QueueSemaphore);
  775.  
  776.         QueueCount++;
  777.  
  778.         ReleaseSemaphore(&QueueSemaphore);
  779.     }
  780.  
  781.     return(Message);
  782. }
  783.  
  784.     /* StartAudio():
  785.      *
  786.      *    Set up the audio device requests to play the currently
  787.      *    available data and start them simultaneously.
  788.      */
  789.  
  790. VOID
  791. StartAudio()
  792. {
  793.         /* So nobody will interrupt us. */
  794.  
  795.     Forbid();
  796.  
  797.     AudioLeft -> ioa_Request . io_Command    = CMD_WRITE;
  798.     AudioLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  799.     AudioLeft -> ioa_Period            = Rate;
  800.     AudioLeft -> ioa_Volume            = 64;
  801.     AudioLeft -> ioa_Cycles            = 1;
  802.     AudioLeft -> ioa_Data            = ThisLeft;
  803.     AudioLeft -> ioa_Length            = FillCounter;
  804.  
  805.         /* Swap the buffers (double buffering). */
  806.  
  807.     ThisLeft = NextLeft;
  808.     NextLeft = AudioLeft -> ioa_Data;
  809.  
  810.     AudioRight -> ioa_Request . io_Command    = CMD_WRITE;
  811.     AudioRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  812.     AudioRight -> ioa_Period        = Rate;
  813.     AudioRight -> ioa_Volume        = 64;
  814.     AudioRight -> ioa_Cycles        = 1;
  815.     AudioRight -> ioa_Data            = ThisRight;
  816.     AudioRight -> ioa_Length        = FillCounter;
  817.  
  818.         /* Swap the buffers (double buffering). */
  819.  
  820.     ThisRight = NextRight;
  821.     NextRight = AudioRight -> ioa_Data;
  822.  
  823.         /* Reset the audio data fill counter. */
  824.  
  825.     FillCounter = 0;
  826.  
  827.         /* Stop playing any sound (= ^S). */
  828.  
  829.     AudioControl -> ioa_Request . io_Command    = CMD_STOP;
  830.     AudioControl -> ioa_Period            = Rate;
  831.  
  832.     BeginIO(AudioControl);
  833.     WaitIO(AudioControl);
  834.  
  835.         /* Prepare to start both audio device requests,
  836.          * the CMD_STOP command will keep them from getting
  837.          * satisfied immediately.
  838.          */
  839.  
  840.     BeginIO(AudioLeft);
  841.     BeginIO(AudioRight);
  842.  
  843.         /* Start playing both channels simultaneously (= ^Q). */
  844.  
  845.     AudioControl -> ioa_Request . io_Command    = CMD_START;
  846.     AudioControl -> ioa_Period            = Rate;
  847.  
  848.     BeginIO(AudioControl);
  849.     WaitIO(AudioControl);
  850.  
  851.         /* Remember current state, so the cleanup code will
  852.          * know what to do.
  853.          */
  854.  
  855.     AudioUsed = AudioActive = TRUE;
  856.  
  857.     Permit();
  858. }
  859.  
  860.     /* ProcessAudio():
  861.      *
  862.      *    Process incoming audio data messages.
  863.      */
  864.  
  865. VOID
  866. ProcessAudio()
  867. {
  868.     struct AudioMessage    *Message;
  869.     LONG             i,j;
  870.     WORD             Left,Right;
  871.  
  872.         /* Loop until done. */
  873.  
  874.     while(Message = (struct AudioMessage *)GetMsg(ChildPort))
  875.     {
  876.             /* Process the single data blocks. */
  877.  
  878.         for(i = 0 ; i < Message -> NumBlocks ; i++)
  879.         {
  880.                 /* Process the samples. */
  881.  
  882.             for(j = 0 ; j < 588 ; j++)
  883.             {
  884.                     /* Well, a bit of explanation might be necessary
  885.                      * to tell you why this code is discarding every
  886.                      * second data block. Each incoming message
  887.                      * supplies data for about one second of music or
  888.                      * sound to be replayed. This accounts for
  889.                      * 44,100 samples per second for each data packet.
  890.                      * Unfortunately, the highest replay rate the Amiga
  891.                      * audio hardware supports at this time of writing
  892.                      * is about 30,000 samples per second. Instead of
  893.                      * scaling the data packet size down to the maximum
  894.                      * the amount of data is halved, thus reducing the
  895.                      * replay rate required to 22,050 samples per second.
  896.                      */
  897.  
  898.                 if(j & 1)
  899.                 {
  900.                         /* Convert the digital audio data (little endian,
  901.                          * sixteen bits per sample, signed).
  902.                          */
  903.  
  904.                     Left    = (((WORD)Message -> Data[i] . Sample[j] . LeftMSB)    << 8) | Message -> Data[i] . Sample[j] . LeftLSB;
  905.                     Right    = (((WORD)Message -> Data[i] . Sample[j] . RightMSB)    << 8) | Message -> Data[i] . Sample[j] . RightLSB;
  906.  
  907.                         /* Scale the sixteen bit values down to eight bits. */
  908.  
  909.                     ThisLeft[FillCounter]    = Left    >> 8;
  910.                     ThisRight[FillCounter]    = Right    >> 8;
  911.  
  912.                         /* One more byte in the buffer... */
  913.  
  914.                     FillCounter++;
  915.                 }
  916.             }
  917.         }
  918.  
  919.             /* Clean up. */
  920.  
  921.         DeleteAudioMessage(Message);
  922.  
  923.             /* Audio output still active? */
  924.  
  925.         if(AudioActive)
  926.         {
  927.             WaitIO(AudioLeft);
  928.             WaitIO(AudioRight);
  929.  
  930.             AudioActive = FALSE;
  931.         }
  932.  
  933.             /* Are we to stop here? */
  934.  
  935.         if(SetSignal(0,0) & SIG_KILL)
  936.             break;
  937.         else
  938.         {
  939.                 /* Replay the data if available. */
  940.  
  941.             if(FillCounter)
  942.                 StartAudio();
  943.         }
  944.     }
  945. }
  946.  
  947.     /* ChildTask():
  948.      *
  949.      *    The audio player task.
  950.      */
  951.  
  952. VOID __saveds
  953. ChildTask()
  954. {
  955.         /* Remember task address. */
  956.  
  957.     Child = SysBase -> ThisTask;
  958.  
  959.         /* Create communications port. */
  960.  
  961.     if(ChildPort = CreateMsgPort())
  962.     {
  963.         struct AudioMessage *Message;
  964.  
  965.             /* Initialize the audio device. */
  966.  
  967.         if(AudioInit())
  968.         {
  969.             ULONG    Signals;
  970.             BOOL    Terminate = FALSE;
  971.  
  972.                 /* Wait for handshake signal. */
  973.  
  974.             Signal(Father,SIG_HANDSHAKE);
  975.  
  976.                 /* Loop until finished or stopped. */
  977.  
  978.             for(;;)
  979.             {
  980.                     /* Wait for a signal... */
  981.  
  982.                 Signals = Wait(SIG_CHILD | SIG_KILL | SIG_SYNC);
  983.  
  984.                     /* The last track to play? */
  985.  
  986.                 if(Signals & SIG_SYNC)
  987.                     Terminate = TRUE;
  988.  
  989.                     /* Stop it, now! */
  990.  
  991.                 if(Signals & SIG_KILL)
  992.                     break;
  993.  
  994.                     /* Process audio data. */
  995.  
  996.                 if(Signals & SIG_CHILD)
  997.                     ProcessAudio();
  998.  
  999.                     /* Wake up the handler task. */
  1000.  
  1001.                 if(FatherWaiting)
  1002.                     Signal(Father,SIG_SYNC);
  1003.  
  1004.                     /* Wait until track is replayed? */
  1005.  
  1006.                 if(Terminate)
  1007.                 {
  1008.                     if(!QueueCount)
  1009.                     {
  1010.                         if(AudioActive)
  1011.                         {
  1012.                             WaitIO(AudioLeft);
  1013.                             WaitIO(AudioRight);
  1014.                         }
  1015.  
  1016.                         break;
  1017.                     }
  1018.                 }
  1019.             }
  1020.  
  1021.                 /* Clean up. */
  1022.  
  1023.             if(Terminate)
  1024.             {
  1025.                 Forbid();
  1026.  
  1027.                 Signal(Father,SIG_HANDSHAKE);
  1028.  
  1029.                 Child = NULL;
  1030.             }
  1031.         }
  1032.  
  1033.             /* Get rid of queued messages. */
  1034.  
  1035.         while(Message = (struct AudioMessage *)GetMsg(ChildPort))
  1036.             DeleteAudioMessage(Message);
  1037.  
  1038.             /* Free the audio resources. */
  1039.  
  1040.         AudioExit();
  1041.  
  1042.             /* Delete the communications port. */
  1043.  
  1044.         DeleteMsgPort(ChildPort);
  1045.  
  1046.         ChildPort = NULL;
  1047.     }
  1048.  
  1049.         /* Finish the rest. */
  1050.  
  1051.     if(Child)
  1052.     {
  1053.         Forbid();
  1054.  
  1055.         Signal(Father,SIG_HANDSHAKE);
  1056.  
  1057.         Child = NULL;
  1058.     }
  1059. }
  1060.  
  1061.     /* CloseAll():
  1062.      *
  1063.      *    The big cleanup routine.
  1064.      */
  1065.  
  1066. VOID
  1067. CloseAll()
  1068. {
  1069.         /* Shut down the scsi device driver. */
  1070.  
  1071.     SCSIExit();
  1072.  
  1073.         /* Remove the player task. */
  1074.  
  1075.     if(Child)
  1076.     {
  1077.         Signal(Child,SIG_KILL);
  1078.  
  1079.         Wait(SIG_HANDSHAKE);
  1080.     }
  1081.  
  1082.         /* Free the command line reader data. */
  1083.  
  1084.     if(ArgsPtr)
  1085.     {
  1086.         FreeDosObject(DOS_RDARGS,ArgsPtr);
  1087.  
  1088.         FreeArgs(ArgsPtr);
  1089.  
  1090.         ArgsPtr = NULL;
  1091.     }
  1092.  
  1093.         /* Free the command line argument data. */
  1094.  
  1095.     if(Arg)
  1096.     {
  1097.         FreeVec(Arg);
  1098.  
  1099.         Arg = NULL;
  1100.     }
  1101.  
  1102.         /* Close the libraries. */
  1103.  
  1104.     if(UtilityBase)
  1105.     {
  1106.         CloseLibrary(UtilityBase);
  1107.  
  1108.         UtilityBase = NULL;
  1109.     }
  1110.  
  1111.     if(DOSBase)
  1112.     {
  1113.         CloseLibrary(DOSBase);
  1114.  
  1115.         DOSBase = NULL;
  1116.     }
  1117. }
  1118.  
  1119.     /* OpenAll():
  1120.      *
  1121.      *    Open the resources required and complain if anything
  1122.      *    goes wrong.
  1123.      */
  1124.  
  1125. BOOL
  1126. OpenAll()
  1127. {
  1128.     STRPTR    Device;
  1129.     LONG    Unit,i;
  1130.     BOOL    GotIt = FALSE;
  1131.  
  1132.         /* Most important ;-) */
  1133.  
  1134.     SysBase = *(struct ExecBase **)4;
  1135.  
  1136.         /* So we know who we are. */
  1137.  
  1138.     Father = (struct Process *)SysBase -> ThisTask;
  1139.  
  1140.         /* Called from Workbench? Oops... */
  1141.  
  1142.     if(!Father -> pr_CLI)
  1143.     {
  1144.         struct Message *Message;
  1145.  
  1146.             /* Wait for startup message. */
  1147.  
  1148.         WaitPort(&Father -> pr_MsgPort);
  1149.  
  1150.             /* Pick it up. */
  1151.  
  1152.         Message = GetMsg(&Father -> pr_MsgPort);
  1153.  
  1154.         Forbid();
  1155.  
  1156.             /* Return it and stop here. */
  1157.  
  1158.         ReplyMsg(Message);
  1159.  
  1160.         return(FALSE);
  1161.     }
  1162.  
  1163.         /* Open the libraries. */
  1164.  
  1165.     if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)))
  1166.         return(FALSE);
  1167.  
  1168.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  1169.     {
  1170.         Printf("CDDA: Could not open utility.library v37.\n");
  1171.  
  1172.         return(FALSE);
  1173.     }
  1174.  
  1175.         /* Set up the semaphore. */
  1176.  
  1177.     InitSemaphore(&QueueSemaphore);
  1178.  
  1179.         /* Allocate command line reader data. */
  1180.  
  1181.     if(!(Arg = (STRPTR *)AllocVec(sizeof(STRPTR) * ARGCOUNT,MEMF_ANY | MEMF_CLEAR)))
  1182.     {
  1183.         PrintFault(ERROR_NO_FREE_STORE,"CDDA");
  1184.  
  1185.         return(FALSE);
  1186.     }
  1187.  
  1188.     if(!(ArgsPtr = AllocDosObjectTags(DOS_RDARGS,TAG_DONE)))
  1189.     {
  1190.         PrintFault(IoErr(),"CDDA");
  1191.  
  1192.         return(FALSE);
  1193.     }
  1194.  
  1195.         /* Just a bit of documentation. */
  1196.  
  1197.     ArgsPtr -> RDA_ExtHelp =    "\nThis  program  replays  digital audio data directly off a compact disc\n"
  1198.                     "using  the Amiga audio hardware (in stereo where available). A special\n"
  1199.                     "type  of  CD-ROM  drive  is required since this program makes use of a\n"
  1200.                     "vendor  unique command supported by Sony drives, such as the CDU-8003A\n"
  1201.                     "or the Apple CD-300 drive.\n\n"
  1202.                     "Please  note  that due to the work involved reading and converting the\n"
  1203.                     "audio  data  music may not always play smoothly. The program will also\n"
  1204.                     "consume  large  amounts  of  chip memory in order to supply the player\n"
  1205.                     "task  with  a  contiguous  stream of data (the maximum number of sound\n"
  1206.                     "queue  packets  can  be adjusted using a command line parameter). Your\n"
  1207.                     "system  may also experience heavy task loading since the incoming data\n"
  1208.                     "(more  than  88K  bytes  per  second)  must  be  handled  quickly  and\n"
  1209.                     "efficiently in order to avoid `pops' and delays.\n\n"
  1210.                     "The command line template looks like this:\n\n"
  1211.                     "DEVICE/K,UNIT/K/N,TRACK/N,FROM/K/N,TO/K/N,NUM/K/N,MAX/K/N,VERBOSE/S\n\n"
  1212.                     "DEVICE  This parameter requires a keyword. By default the program will\n"
  1213.                     "        address `scsi.device' as the device driver which controls your\n"
  1214.                     "        CD-ROM  drive.  You  can  override this by using the following\n"
  1215.                     "        command line option:\n\n"
  1216.                     "                        DEVICE <device name>\n\n"
  1217.                     "        Example:        DEVICE gvpscsi.device\n\n"
  1218.                     "UNIT    This parameter requires a keyword. By default the program will\n"
  1219.                     "        expect  your  CD-ROM drive to respond to device unit number 2.\n"
  1220.                     "        You  can  override  this  by  using the following command line\n"
  1221.                     "        options:\n\n"
  1222.                     "                        UNIT <unit number>\n\n"
  1223.                     "        Example:        UNIT 3\n\n"
  1224.                     "TRACK   This  parameter  requires  a keyword. Each data/music track on\n"
  1225.                     "        the CD has a unique number assigned which ranges from 1 to 99.\n"
  1226.                     "        This is how you choose which track to replay.\n\n"
  1227.                     "        Example:        TRACK 1\n\n"
  1228.                     "FROM    This  parameter requires a keyword. The CD consists of several\n"
  1229.                     "        sectors, each of which can be addressed independently. Several\n"
  1230.                     "        sectors form a track, 75 sectors of data make up one second of\n"
  1231.                     "        audio  data.  This  is how you choose which sectors to replay,\n"
  1232.                     "        note  that  this  parameter  requires  the  \"TO\"  or the \"NUM\"\n"
  1233.                     "        parameter.\n\n"
  1234.                     "        Example:        FROM 1 TO 600\n\n"
  1235.                     "TO      This  parameter  requires  a  keyword.  It works both with the\n"
  1236.                     "        \"TRACK\" and \"FROM\" parameters.\n\n"
  1237.                     "        Example:        TRACK 1 TO 5    Plays tracks to 1 to 5\n"
  1238.                     "                        FROM 1 TO 600   Plays sectors 1 to 600\n\n"
  1239.                     "NUM     This  parameter  requires  a  keyword.  It works both with the\n"
  1240.                     "        \"TRACK\" and \"FROM\" parameters.\n\n"
  1241.                     "        Example:        TRACK 3 NUM 7   Plays tracks to 3 to 10\n"
  1242.                     "                        FROM 2 NUM 4    Plays sectors 2 to 6\n\n"
  1243.                     "MAX     This  parameter  requires  a  keyword.  In  order  to  feed  a\n"
  1244.                     "        contiguous  stream  of  data to the player task incoming audio\n"
  1245.                     "        data  is  queued. The maximum number of data packets queued is\n"
  1246.                     "        set  using this parameter. By default the number of packets is\n"
  1247.                     "        set to 3. Each packet requires about 176K bytes, so take care.\n\n"
  1248.                     "        Example:        MAX 5\n\n"
  1249.                     "VERBOSE This command line option will enable some more or less helpful\n"
  1250.                     "        progress messages, may not be of any use at all.\n\n"
  1251.                     "        Example:        VERBOSE\n\n"
  1252.                     "That's  all  folks!  This program and the accompanying source code are\n"
  1253.                     "freeware. Respect copyright, encourage creativity.\n\n"
  1254.                     TEMPLATE;
  1255.  
  1256.         /* Read the command line arguments. */
  1257.  
  1258.     if(!ReadArgs(TEMPLATE,(LONG *)Arg,ArgsPtr))
  1259.     {
  1260.         PrintFault(IoErr(),"CDDA");
  1261.  
  1262.         return(FALSE);
  1263.     }
  1264.  
  1265.         /* Did we get what we need? */
  1266.  
  1267.     if((!Arg[ARG_TRACK] && !Arg[ARG_FROM]) || (Arg[ARG_FROM] && !Arg[ARG_TO] && !Arg[ARG_NUM]))
  1268.     {
  1269.         PrintFault(ERROR_REQUIRED_ARG_MISSING,"CDDA");
  1270.  
  1271.         return(FALSE);
  1272.     }
  1273.  
  1274.         /* Get the scsi device name. */
  1275.  
  1276.     if(Arg[ARG_DEVICE])
  1277.         Device = Arg[ARG_DEVICE];
  1278.     else
  1279.         Device = SCSI_DEVICE;
  1280.  
  1281.         /* Get the scsi device unit number. */
  1282.  
  1283.     if(Arg[ARG_UNIT])
  1284.         Unit = *(LONG *)Arg[ARG_UNIT];
  1285.     else
  1286.         Unit = SCSI_UNIT;
  1287.  
  1288.         /* Verbose operation? */
  1289.  
  1290.     if(Arg[ARG_VERBOSE])
  1291.         Verbose = TRUE;
  1292.     else
  1293.         Verbose = FALSE;
  1294.  
  1295.         /* Create the player task. */
  1296.  
  1297.     Forbid();
  1298.  
  1299.     if(CreateTask("« CDDA Player task »",CHILD_PRI,ChildTask,CHILD_STACK))
  1300.     {
  1301.         SetSignal(0,SIG_HANDSHAKE);
  1302.  
  1303.         Wait(SIG_HANDSHAKE);
  1304.     }
  1305.  
  1306.     Permit();
  1307.  
  1308.     if(!Child)
  1309.     {
  1310.         Printf("CDDA: Failed to launch player task.\n");
  1311.  
  1312.         return(FALSE);
  1313.     }
  1314.  
  1315.         /* Set up the scsi device driver. */
  1316.  
  1317.     if(!SCSIInit(Device,Unit))
  1318.     {
  1319.         Printf("CDDA: Failed to open \"%s\" unit #%ld.\n",Device,Unit);
  1320.  
  1321.         return(FALSE);
  1322.     }
  1323.  
  1324.         /* Get things going, after a medium is removed/inserted
  1325.          * the first command will always fail.
  1326.          */
  1327.  
  1328.     TestUnitReady();
  1329.  
  1330.         /* Inquire device parameters. */
  1331.  
  1332.     if(Inquire())
  1333.     {
  1334.         Printf("CDDA: Cannot read device parameters of \"%s\" unit #%ld.\n",Device,Unit);
  1335.  
  1336.         return(FALSE);
  1337.     }
  1338.  
  1339.         /* We need a device to conform to the SCSI-2 specs, or we
  1340.          * will be unable to read the table of contents.
  1341.          */
  1342.  
  1343.     if((InquiryData . Version & 0x07) < 2)
  1344.     {
  1345.         Printf("CDDA: CD-ROM device must conform to the SCSI-2 specification..\n");
  1346.  
  1347.         return(FALSE);
  1348.     }
  1349.  
  1350.         /* Is this really a CD-ROM drive? */
  1351.  
  1352.     if((InquiryData . PeripheralType & 0x1F) != 0x05)
  1353.     {
  1354.         Printf("CDDA: \"%s\" unit #%ld is not a CD-ROM device.\n",Device,Unit);
  1355.  
  1356.         return(FALSE);
  1357.     }
  1358.  
  1359.         /* Is there a CD present in the drive? */
  1360.  
  1361.     if(TestUnitReady())
  1362.     {
  1363.         Printf("CDDA: No CD in \"%s\" unit #%ld\n",Device,Unit);
  1364.  
  1365.         return(FALSE);
  1366.     }
  1367.  
  1368.         /* Read the table of contents. */
  1369.  
  1370.     if(ReadTOC())
  1371.     {
  1372.         Printf("CDDA: Failed to read table of contents.\n");
  1373.  
  1374.         return(FALSE);
  1375.     }
  1376.  
  1377.         /* Track number given? */
  1378.  
  1379.     if(Arg[ARG_TRACK])
  1380.     {
  1381.         LONG Track = *(LONG *)Arg[ARG_TRACK],To;
  1382.  
  1383.             /* Track number too low? */
  1384.  
  1385.         if(Track < FullTOC . FirstTrack)
  1386.         {
  1387.             Printf("CDDA: The first available track is #%ld, not #%ld.\n",FullTOC . FirstTrack,Track);
  1388.  
  1389.             return(FALSE);
  1390.         }
  1391.  
  1392.             /* Track number too high? */
  1393.  
  1394.         if(Track > FullTOC . LastTrack)
  1395.         {
  1396.             Printf("CDDA: There are only %ld tracks on this CD, not %ld.\n",FullTOC . LastTrack,Track);
  1397.  
  1398.             return(FALSE);
  1399.         }
  1400.  
  1401.             /* Stop track given? */
  1402.  
  1403.         if(Arg[ARG_TO])
  1404.             To = *(LONG *)Arg[ARG_TO];
  1405.         else
  1406.         {
  1407.                 /* Number of tracks to replay given? */
  1408.  
  1409.             if(Arg[ARG_NUM])
  1410.                 To = Track + *(LONG *)Arg[ARG_NUM] - 1;
  1411.             else
  1412.                 To = Track;
  1413.         }
  1414.  
  1415.             /* Make sure that the stop value makes sense. */
  1416.  
  1417.         if(To < Track)
  1418.             To = Track;
  1419.  
  1420.         if(To > FullTOC . LastTrack)
  1421.             To = FullTOC . LastTrack;
  1422.  
  1423.             /* Find the correct sector offsets. */
  1424.  
  1425.         for(i = 0 ; i < FullTOC . LastTrack - FullTOC . FirstTrack + 1 ; i++)
  1426.         {
  1427.             if(FullTOC . TOC[i] . TrackNumber == Track)
  1428.             {
  1429.                 Index    = FullTOC . TOC[i] . Address;
  1430.                 Total    = FullTOC . TOC[i + (To - Track) + 1] . Address - FullTOC . TOC[i] . Address;
  1431.                 GotIt    = TRUE;
  1432.  
  1433.                 break;
  1434.             }
  1435.         }
  1436.  
  1437.             /* Successful? */
  1438.  
  1439.         if(!GotIt)
  1440.         {
  1441.             Printf("CDDA: Failed to find track #%ld.\n",*(LONG *)Arg[ARG_TRACK]);
  1442.  
  1443.             return(FALSE);
  1444.         }
  1445.     }
  1446.     else
  1447.     {
  1448.             /* Get the first sector number to play. */
  1449.  
  1450.         Index = *(LONG *)Arg[ARG_FROM];
  1451.  
  1452.             /* Are we to replay a number of sectors
  1453.              * or are we to replay the audio data
  1454.              * between a start and a stop sector?
  1455.              */
  1456.  
  1457.         if(Arg[ARG_NUM])
  1458.             Total = *(LONG *)Arg[ARG_NUM];
  1459.         else
  1460.             Total = *(LONG *)Arg[ARG_TO] - Index;
  1461.     }
  1462.  
  1463.     GotIt = FALSE;
  1464.  
  1465.         /* Verify the offsets given. */
  1466.  
  1467.     for(i = FullTOC . LastTrack - FullTOC . FirstTrack ; i >= 0 ; i--)
  1468.     {
  1469.             /* Is this the track we want? */
  1470.  
  1471.         if(FullTOC . TOC[i] . Address <= Index)
  1472.         {
  1473.             LONG Size;
  1474.  
  1475.                 /* No chance to replay raw data, this could
  1476.                  * be a CD-ROM track.
  1477.                  */
  1478.  
  1479.             if(FullTOC . TOC[i] . Control & (1 << 2))
  1480.             {
  1481.                 Printf("CDDA: Can only replay digital audio data.\n");
  1482.  
  1483.                 return(FALSE);
  1484.             }
  1485.  
  1486.                 /* No quadraphonics, please. */
  1487.  
  1488.             if(FullTOC . TOC[i] . Control & (1 << 3))
  1489.             {
  1490.                 Printf("CDDA: Can only replay two channel audio data.\n");
  1491.  
  1492.                 return(FALSE);
  1493.             }
  1494.  
  1495.             GotIt = TRUE;
  1496.  
  1497.                 /* Calculate the number of sectors involved. */
  1498.  
  1499.             Size = FullTOC . TOC[i + 1] . Address - FullTOC . TOC[i] . Address;
  1500.  
  1501.                 /* Too many requested? */
  1502.  
  1503.             if(Total > Size)
  1504.             {
  1505.                 if(Verbose)
  1506.                     Printf("CDDA: Too many sectors requested, truncating.\n");
  1507.  
  1508.                 Total = Size;
  1509.             }
  1510.  
  1511.             break;
  1512.         }
  1513.     }
  1514.  
  1515.     if(!GotIt)
  1516.     {
  1517.         Printf("CDDA: Failed to find sector #%ld.\n",Index);
  1518.  
  1519.         return(FALSE);
  1520.     }
  1521.  
  1522.     return(TRUE);
  1523. }
  1524.  
  1525.     /* ReadCDDASectors(APTR Buffer,LONG From,LONG Count):
  1526.      *
  1527.      *    Read digital audio data.
  1528.      */
  1529.  
  1530. BYTE
  1531. ReadCDDASectors(APTR Buffer,LONG From,LONG Count)
  1532. {
  1533.     STATIC struct ReadCDDA ReadCDDA;
  1534.  
  1535.         /* Set up the read command. */
  1536.  
  1537.     ReadCDDA . Command            = 0xD8;
  1538.     ReadCDDA . Pad                = 0;
  1539.     ReadCDDA . Address            = From;
  1540.     ReadCDDA . Count            = Count;
  1541.     ReadCDDA . SubCode            = 0;
  1542.     ReadCDDA . Control            = 0;
  1543.  
  1544.         /* Set up the SCSI direct command. */
  1545.  
  1546.     SCSIRequest -> iotd_Req . io_Command    = HD_SCSICMD;
  1547.     SCSIRequest -> iotd_Req . io_Data    = &SCSICmd;
  1548.     SCSIRequest -> iotd_Req . io_Length    = sizeof(struct SCSICmd);
  1549.  
  1550.     SCSICmd . scsi_Data            = Buffer;
  1551.     SCSICmd . scsi_Length            = Count * sizeof(struct CDDASector);
  1552.     SCSICmd . scsi_Actual            = 0;
  1553.     SCSICmd . scsi_Command            = (UBYTE *)&ReadCDDA;
  1554.     SCSICmd . scsi_CmdLength        = sizeof(struct ReadCDDA);
  1555.     SCSICmd . scsi_CmdActual        = 0;
  1556.     SCSICmd . scsi_Flags            = SCSIF_READ | SCSIF_AUTOSENSE;
  1557.     SCSICmd . scsi_SenseData        = SenseBuffer;
  1558.     SCSICmd . scsi_SenseLength        = 255;
  1559.     SCSICmd . scsi_SenseActual        = 0;
  1560.  
  1561.     return(DoIO(SCSIRequest));
  1562. }
  1563.  
  1564.     /* TestUnitReady():
  1565.      *
  1566.      *    Check to see whether the unit thinks it is ready
  1567.      *    to receive and process commands or not.
  1568.      */
  1569.  
  1570. BYTE
  1571. TestUnitReady()
  1572. {
  1573.     STATIC struct TestUnitReady TestUnitReady;
  1574.  
  1575.         /* Set up the test command (all zeroes). */
  1576.  
  1577.     memset(&TestUnitReady,0,sizeof(struct TestUnitReady));
  1578.  
  1579.         /* Set up the SCSI direct command. */
  1580.  
  1581.     SCSIRequest -> iotd_Req . io_Command    = HD_SCSICMD;
  1582.     SCSIRequest -> iotd_Req . io_Data    = &SCSICmd;
  1583.     SCSIRequest -> iotd_Req . io_Length    = sizeof(struct SCSICmd);
  1584.  
  1585.     SCSICmd . scsi_Length            = 0;
  1586.     SCSICmd . scsi_Actual            = 0;
  1587.     SCSICmd . scsi_Command            = (UBYTE *)&TestUnitReady;
  1588.     SCSICmd . scsi_CmdLength        = sizeof(struct TestUnitReady);
  1589.     SCSICmd . scsi_CmdActual        = 0;
  1590.     SCSICmd . scsi_Flags            = SCSIF_READ | SCSIF_AUTOSENSE;
  1591.     SCSICmd . scsi_SenseData        = SenseBuffer;
  1592.     SCSICmd . scsi_SenseLength        = 255;
  1593.     SCSICmd . scsi_SenseActual        = 0;
  1594.  
  1595.     return(DoIO(SCSIRequest));
  1596. }
  1597.  
  1598.     /* ReadTOC():
  1599.      *
  1600.      *    Read the table of contents.
  1601.      */
  1602.  
  1603. BYTE
  1604. ReadTOC()
  1605. {
  1606.     STATIC struct ReadTOC ReadTOC;
  1607.  
  1608.         /* Set up the read command. */
  1609.  
  1610.     memset(&ReadTOC,0,sizeof(struct ReadTOC));
  1611.  
  1612.     ReadTOC . Command            = 0x43;
  1613.     ReadTOC . Alloc1            = sizeof(struct FullTOC) >> 8;
  1614.     ReadTOC . Alloc2            = sizeof(struct FullTOC) & 0xFF;
  1615.  
  1616.         /* Set up the SCSI direct command. */
  1617.  
  1618.     SCSIRequest -> iotd_Req . io_Command    = HD_SCSICMD;
  1619.     SCSIRequest -> iotd_Req . io_Data    = &SCSICmd;
  1620.     SCSIRequest -> iotd_Req . io_Length    = sizeof(struct SCSICmd);
  1621.  
  1622.     SCSICmd . scsi_Data            = (UWORD *)&FullTOC;
  1623.     SCSICmd . scsi_Length            = sizeof(struct FullTOC);
  1624.     SCSICmd . scsi_Actual            = 0;
  1625.     SCSICmd . scsi_Command            = (UBYTE *)&ReadTOC;
  1626.     SCSICmd . scsi_CmdLength        = sizeof(struct ReadTOC);
  1627.     SCSICmd . scsi_CmdActual        = 0;
  1628.     SCSICmd . scsi_Flags            = SCSIF_READ | SCSIF_AUTOSENSE;
  1629.     SCSICmd . scsi_SenseData        = SenseBuffer;
  1630.     SCSICmd . scsi_SenseLength        = 255;
  1631.     SCSICmd . scsi_SenseActual        = 0;
  1632.  
  1633.     return(DoIO(SCSIRequest));
  1634. }
  1635.  
  1636.     /* Inquire():
  1637.      *
  1638.      *    Inquire hard-coded device parameters.
  1639.      */
  1640.  
  1641. BYTE
  1642. Inquire()
  1643. {
  1644.     STATIC struct Inquiry Inquiry;
  1645.  
  1646.         /* Set up the inquiry command. */
  1647.  
  1648.     memset(&Inquiry,0,sizeof(struct Inquiry));
  1649.  
  1650.     Inquiry . Command            = 0x12;
  1651.     Inquiry . AllocationLength        = sizeof(struct InquiryData);
  1652.  
  1653.         /* Set up the SCSI direct command. */
  1654.  
  1655.     SCSIRequest -> iotd_Req . io_Command    = HD_SCSICMD;
  1656.     SCSIRequest -> iotd_Req . io_Data    = &SCSICmd;
  1657.     SCSIRequest -> iotd_Req . io_Length    = sizeof(struct SCSICmd);
  1658.  
  1659.     SCSICmd . scsi_Data            = (UWORD *)&InquiryData;
  1660.     SCSICmd . scsi_Length            = sizeof(struct InquiryData);
  1661.     SCSICmd . scsi_Actual            = 0;
  1662.     SCSICmd . scsi_Command            = (UBYTE *)&Inquiry;
  1663.     SCSICmd . scsi_CmdLength        = sizeof(struct Inquiry);
  1664.     SCSICmd . scsi_CmdActual        = 0;
  1665.     SCSICmd . scsi_Flags            = SCSIF_READ | SCSIF_AUTOSENSE;
  1666.     SCSICmd . scsi_SenseData        = SenseBuffer;
  1667.     SCSICmd . scsi_SenseLength        = 255;
  1668.     SCSICmd . scsi_SenseActual        = 0;
  1669.  
  1670.     return(DoIO(SCSIRequest));
  1671. }
  1672.